package com.night.icm.service.business.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.common.utils.TermType;
import com.night.icm.model.business.CourseTeacherDTO;
import com.night.icm.persistence.base.entity.Course;
import com.night.icm.persistence.base.entity.Teacher;
import com.night.icm.persistence.base.repository.CourseRepository;
import com.night.icm.persistence.base.repository.TeacherRepository;
import com.night.icm.persistence.business.entity.CourseTeacher;
import com.night.icm.persistence.business.reporsitory.CourseTeacherRepository;
import com.night.icm.service.business.mapper.CourseTeacherMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * CourseTeacherServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/2/14
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class CourseTeacherServiceImpl implements CourseTeacherService {

    private final CourseTeacherRepository courseTeacherRepository;
    private final CourseTeacherMapper courseTeacherMapper;
    private final CourseRepository courseRepository;
    private final TeacherRepository teacherRepository;

    @Autowired
    public CourseTeacherServiceImpl(CourseTeacherRepository courseTeacherRepository, CourseTeacherMapper courseTeacherMapper, CourseRepository courseRepository, TeacherRepository teacherRepository) {
        this.courseTeacherRepository = courseTeacherRepository;
        this.courseTeacherMapper = courseTeacherMapper;
        this.courseRepository = courseRepository;
        this.teacherRepository = teacherRepository;
    }

    /**
     * 分页查找开课信息
     *
     * @param page        页号，从0开始
     * @param size        每页记录条数
     * @param sort        排序字段，例如：字段1,asc,字段2,desc
     * @param year        所属年度
     * @param termType    所属学期
     * @param courseName  课程名称
     * @param teacherName 授课教师
     * @param isOpen      是否开课
     * @return 开课信息
     */
    @Override
    public PageDataDTO<CourseTeacherDTO> findOnePage(int page, int size, String sort, String year, TermType termType, String courseName, String teacherName, Boolean isOpen) {
        PredicateBuilder<CourseTeacher> pb = Specifications.<CourseTeacher>and()
                .eq(StringUtils.isNotBlank(year), "year", year)
                .eq(null != termType, "termType", termType)
                .like(StringUtils.isNotBlank(courseName), "course.name", "%" + courseName + "%")
                .like(StringUtils.isNotBlank(teacherName), "teacher.name", "%" + teacherName + "%")
                .eq(null != isOpen, "isOpen", isOpen);
        Page<CourseTeacher> page1 = this.courseTeacherRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<CourseTeacherDTO> dtos = this.courseTeacherMapper.toList(page1.getContent());
        return PageDataUtil.toPageData(page1, dtos);
    }

    /**
     * 添加开课信息
     *
     * @param courseTeacherDTO 开课信息
     * @return 开课信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseTeacherDTO create(CourseTeacherDTO courseTeacherDTO) {
        CourseTeacher courseTeacher = this.courseTeacherMapper.toEntity(courseTeacherDTO);

        // 关联课程
        courseTeacher.setCourse(courseTeacher.getCourse());
        this.courseTeacherRepository.save(courseTeacher);
        // 关联教师
        courseTeacher.setTeacher(courseTeacher.getTeacher());
        this.courseTeacherRepository.save(courseTeacher);
        return this.courseTeacherMapper.toDTO(courseTeacher);
    }

    /**
     * 根据id查找课程类型信息
     *
     * @param id 课程id
     * @return 课程
     */
    private Course getCourseById(String id) {
        Optional<Course> optionalCourse = this.courseRepository.findById(Long.valueOf(id));
        if (!optionalCourse.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalCourse.get();
    }

    /**
     * 根据id查找教师信息
     *
     * @param id 教师id
     * @return 教师
     */
    private Teacher getTeacherById(String id) {
        Optional<Teacher> optionalTeacher = this.teacherRepository.findById(Long.valueOf(id));
        if (!optionalTeacher.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalTeacher.get();
    }

    /**
     * 根据id删除开课信息
     *
     * @param id 开课信息id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        this.courseTeacherRepository.deleteById(Long.valueOf(id));
    }

    /**
     * 更新开课信息
     *
     * @param id               开课信息id
     * @param courseTeacherDTO 开课信息
     * @return 开课信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseTeacherDTO update(String id, CourseTeacherDTO courseTeacherDTO) {
        CourseTeacher courseTeacher = this.getOne(id);
        Long courseId = courseTeacher.getCourse().getId();
        Long teacherId = courseTeacher.getTeacher().getId();
        this.courseTeacherMapper.updateEntity(courseTeacherDTO, courseTeacher);
        if (!courseId.equals(Long.valueOf(courseTeacherDTO.getCourse().getId()))) {
            // 如果所属课程有变化，则修改所属课程
            Course course = this.getCourseById(courseTeacherDTO.getCourse().getId());
            courseTeacher.setCourse(course);
        }
        if (!teacherId.equals(Long.valueOf(courseTeacherDTO.getTeacher().getId()))) {
            // 如果授课教师有变化，则修改授课教师
            Teacher teacher = this.getTeacherById(courseTeacherDTO.getTeacher().getId());
            courseTeacher.setTeacher(teacher);
        }
        this.courseTeacherRepository.save(courseTeacher);
        return this.courseTeacherMapper.toDTO(courseTeacher);
    }

    /**
     * 根据id查找开课信息
     *
     * @param id 开课信息id
     * @return 开课信息
     */
    @Override
    public CourseTeacherDTO findById(String id) {
        CourseTeacher courseTeacher = this.getOne(id);
        return this.courseTeacherMapper.toDTO(courseTeacher);
    }

    /**
     * 查找所有开课课程
     *
     * @param param   排序参数
     * @param pattern 排序模式: asc/desc
     */
    @Override
    public List<CourseTeacherDTO> findAll(String param, String pattern) {
        String keyType = "asc";
        Sort sort;
        if (keyType.equals(pattern)) {
            sort = new Sort(Sort.Direction.ASC, param);
        } else {
            sort = new Sort(Sort.Direction.DESC, param);
        }
        List<CourseTeacher> all = this.courseTeacherRepository.findAll(sort);
        return this.courseTeacherMapper.toList(all);
    }

    /**
     * 根据id获取开课信息
     *
     * @param id 开课id
     * @return 开课信息
     */
    private CourseTeacher getOne(String id) {
        Optional<CourseTeacher> optionalCourseTeacher = this.courseTeacherRepository.findById(Long.valueOf(id));
        if (!optionalCourseTeacher.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalCourseTeacher.get();
    }
}